Skip to content

Conversation

@hyongtao-code
Copy link
Contributor

@hyongtao-code hyongtao-code commented Jan 11, 2026

BufferedReader.read1() could leave the buffered object in a
reentrant (locked) state when an exception was raised while
allocating the output buffer.

This change ensures the internal buffered lock is always released
on error, keeping the object in a consistent state after failures.

BufferedReader.read1() could leave the buffered object in a
reentrant (locked) state when an exception was raised while
allocating the output buffer.

This change ensures the internal buffered lock is always released
on error, keeping the object in a consistent state after failures.

Signed-off-by: Yongtao Huang <yongtaoh2022@gmail.com>
Copy link
Contributor

@cmaloney cmaloney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the patch! The fix looks correct. The NEWs entry and test don't quite match the preferred patterns in CPython, left some comments.

hyongtao-code and others added 2 commits January 12, 2026 06:30
…zHJ2W.rst

Co-authored-by: Cody Maloney <cmaloney@users.noreply.github.com>
@hyongtao-code
Copy link
Contributor Author

The NEWs entry and test don't quite match the preferred patterns in CPython,

Thanks for the review and feedback — I’ve made the requested changes.

@unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform')
@unittest.skipIf(check_sanitizer(thread=True),
'ThreadSanitizer aborts on huge allocations (exit code 66).')
def test_read1_error_does_not_cause_reentrant_failure(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it need @bigmemtest decorator?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. I don’t think @bigmemtest is needed here, since the goal is only to trigger the “request too large → failure” error path, not to actually allocate a large amount of memory.

self.assertIsInstance(cm.exception.__cause__, TypeError)

@unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform')
@unittest.skipIf(check_sanitizer(thread=True),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will other sanitizers work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the non-free-threaded TSan build failed; the UBSan and free-threaded TSan builds are both OK.

Please refer to https://github.com/python/cpython/actions/runs/20896527108/job/60035968975?pr=143690


with self.open(os_helper.TESTFN, "rb", buffering=0) as raw:
bufio = self.tp(raw, buffer_size=8)
huge = 10**18
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would love to see a comment, why this number is used :)

What are the rules for it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion — I’ve switched to using sys.maxsize and added a comment explaining the rationale.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants